home *** CD-ROM | disk | FTP | other *** search
- /*
- Copyright (c) Robert Ramey 1991. All Rights Reserved
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <limits.h>
- #include "psort.h"
- #include "arg.h"
- #include "key.h"
-
- #define MAX_KEYS 32
- #define NSIZE 16
-
- unsigned int key_count = 0; /* number of keys specified by command line */
- KEY key[MAX_KEYS]; /* table of keys specified in command line */
-
- size_t
- tab_count = 0, /* number of fields to count in input record */
- data_offset = 0, /* start additional data used for sorting */
- *tab = (size_t)NULL, /* array of pointers to fields */
- record_offset = 1; /* start of original record data */
-
- SEQ *n_seq = (SEQ *)NULL;
-
- SEQ *seq;
-
- void
- key_create(unsigned int, unsigned int, SEQ *, unsigned int,
- unsigned int, BOOLEAN);
- void
- key_table();
- /*********************************************************************
- structure for accumulating on keys from information from command line
- **********************************************************************/
- struct {
- struct {
- BOOLEAN specified;
- int
- start,
- size;
- } field, /* field specification */
- disp; /* character displacement specification */
- BOOLEAN iflag; /* inverted sequence flag for this field */
- BOOLEAN nflag; /* key field is a numeric value */
- SEQ *seq; /* pointer to sequence table */
- } key_spec;
-
- /*********************************************************************
- key_init - initialize information on keys from command line
- **********************************************************************/
- void
- key_init(argc, argv)
- unsigned int argc;
- char *argv[];
- {
- RANGE range;
- unsigned int i, j, l, seq_value, pseq_value;
- int k;
-
- /* set up defaults */
- key_spec.field.specified = FALSE;
- key_spec.field.start = 0;
- key_spec.field.size = 0;
- key_spec.disp.specified = FALSE;
- key_spec.disp.start = 0;
- key_spec.disp.size = UINT_MAX;
- key_spec.seq = (SEQ *)NULL;
- key_spec.nflag = FALSE;
- key_spec.iflag = FALSE;
-
- /* set up default collating sequence */
- /* which consists of printable characters */
- key_spec.seq = (SEQ *)malloc(sizeof(SEQ));
- if(key_spec.seq == (SEQ *)NULL)
- error("Couldn't get space for default collating sequence");
- for(i = 0; i < 256; ++i)
- key_spec.seq->value[i] = 0;
- j = 0;
- for(i = ' '; i <= '~'; ++i)
- key_spec.seq->value[i] = ++j;
- key_spec.seq->order = j;
-
- /* analize arguments in command line */
- for(i = 0; ++i < argc;){
- if(argv[i][0] != '-' || argv[i][2] != '\0'){
- continue;
- }
- switch(argv[i][1]){
- default:
- continue;
- case 'f': case 'F':
- argv[i] = "";
- if(key_spec.field.specified)
- key_table();
- key_spec.field.specified = TRUE;
- key_spec.disp.start = 0;
- key_spec.disp.size = UINT_MAX;
- arg_range(argv[++i], &range);
- key_spec.field.start = range.start;
- key_spec.field.size = range.end - range.start;
- break;
- case 'c': case 'C':
- argv[i] = "";
- if(key_spec.disp.specified)
- key_table();
- key_spec.disp.specified = TRUE;
- arg_range(argv[++i], &range);
- if(range.end > range.start)
- error("Invalid character displacement range");
- key_spec.disp.start = range.start;
- key_spec.disp.size = range.end - range.start + 1;
- break;
- case 'n': case 'N':
- key_spec.nflag = TRUE;
- ++record_offset;
- if(n_seq == (SEQ *)NULL){
- n_seq = (SEQ *)malloc(sizeof(SEQ));
- if(n_seq == (SEQ *)NULL)
- error("Couldn't get space for sign sequence");
- /* set up collating sequence for - sign */
- for(j = 0;j < 256;++j)
- n_seq->value[j++] = 0;
- j = 0;
- for(k = -NSIZE; k < 0; ++k)
- n_seq->value[k & 0xff] = ++j;
- for(k = 1; k <= NSIZE; ++k)
- n_seq->value[k & 0xff] = ++j;
- n_seq->order = j;
- }
- break;
- case 'i': case 'I':
- key_spec.iflag = TRUE;
- break;
- case 'k': case 'K':
- if(i + 1 == argc)
- break;
- key_spec.iflag = FALSE;
- key_spec.nflag = FALSE;
- key_spec.seq = (SEQ *)malloc(sizeof(SEQ));
- if(key_spec.seq == (SEQ *)NULL)
- error("Couldn't get space for collating sequence");
- for(j = 0; j < 256 ;++j)
- key_spec.seq->value[j] = 0;
- key_spec.seq->order = 0;
- if(key_spec.seq == (SEQ *)NULL)
- error("Couldn't get memory for a sequence table");
- pseq_value = 0;
- case 'r': case 'R':
- argv[i++] = "";
- seq_value = pseq_value;
- while(i < argc && argv[i][0] != NULL && argv[i][0] != '-'){
- pseq_value = seq_value;
- arg_range(argv[i], &range);
- k = range.start < range.end ? +1 : -1;
- for(j = range.start;;j += k){
- key_spec.seq->value[j] = ++seq_value;
- if(j == range.end)
- break;
- }
- argv[i++] = "";
- }
- key_spec.seq->order = seq_value;
- --i;
- continue;
- }
- argv[i] = "";
- }
- /* every sort must have at least one key */
- if(key_count == 0)
- key_table();
-
- tab_count += 2;
- tab = malloc(tab_count * sizeof(int));
- if(tab == (size_t *)NULL)
- error("Couldn't get memory for tab array");
-
- data_offset = sizeof(unsigned int) * (key_count + 1);
- record_offset += data_offset;
-
- return;
- }
- /*********************************************************************
- key_table - create key table entries from command line information
- **********************************************************************/
- private
- void
- key_table()
- {
- unsigned int i, j;
- int k;
-
- i = key_spec.field.start;
- j = i + key_spec.field.size;
- k = key_spec.field.size < 0 ? -1 : 1 ;
- tab_count = max(tab_count, i);
- tab_count = max(tab_count, j);
- for(;;){
- if(!key_spec.nflag){
- key_create(key_spec.disp.start, key_spec.disp.size,
- key_spec.seq, i, DEFAULT, key_spec.iflag);
- }
- else{
- key_create(key_spec.disp.start, 1,
- n_seq, i, SIGN, key_spec.iflag);
- key_create(key_spec.disp.start, UINT_MAX,
- key_spec.seq, i, NUMERIC, key_spec.iflag);
- key_create(key_spec.disp.start, UINT_MAX,
- key_spec.seq, i, FRACTION, key_spec.iflag);
- }
- if(i == j)
- break;
- else
- i += k;
- }
- return;
- }
- /*********************************************************************
- key_create - add a key structure to the table
- **********************************************************************/
- private
- void
- key_create(disp, size, seq, rfield, key_type, iflag)
- unsigned int
- disp, size, rfield, key_type;
- BOOLEAN iflag;
- SEQ *seq;
- {
- KEY *key_ptr;
-
- if(MAX_KEYS == key_count)
- error("Too many key fields used");
-
- key_ptr = &key[key_count++];
- key_ptr->disp = disp;
- key_ptr->size = size;
- key_ptr->rfield = rfield;
- key_ptr->key_type = key_type;
- key_ptr->inverted = iflag;
- key_ptr->seq = seq;
- return;
- }
-